// ***********************************************************************
// Assembly         : GeYiHome.Domain
// Author           : Mr.Fucker
// Created          : 03-17-2017
//
// Last Modified By : Mr.Fucker
// Last Modified On : 03-20-2017
// ***********************************************************************
// <copyright file="EcgCloudDbContext.cs" company="">
//     Copyright ©  2017
// </copyright>
// <summary></summary>
// ***********************************************************************

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using BSF.EntityFramework.Core;
using GeYiHome.Db.DbMapping;
using GeYiHome.Db.Migrations;
using GeYiHome.Domain.Entities;
using GeYiHome.Domain.Specification.SpecAbstract;
using GeYiHome.PublicLibrary;
using GeYiHome.PublicLibrary.Extension;

namespace GeYiHome.Db.DbContent
{
    /// <summary>
    /// Class EcgCloudDbContext.
    /// </summary>
    /// <seealso cref="BSF.EntityFramework.Core.EFDbContextBase" />
    [DbConfigurationType(typeof(MySql.Data.Entity.MySqlEFConfiguration))]
    public class EcgCloudDbContext : EFDbContextBase
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="EcgCloudDbContext"/> class.
        /// </summary>
        public EcgCloudDbContext()
            : base("name=ECGCloudDb")
        {
            Database.SetInitializer(new CreateDatabaseIfNotExists<EcgCloudDbContext>());
        }

        #region Method

        /// <summary>
        /// 获取所有对象
        /// </summary>
        /// <typeparam name="TEntity">The type of the t entity.</typeparam>
        /// <returns>IQueryable&lt;TEntity&gt;.</returns>
        public virtual IQueryable<TEntity> GetAll<TEntity>() where TEntity : BaseEntity
        {
            return this.Set<TEntity>();
        }

        /// <summary>
        /// 修改对象
        /// </summary>
        /// <typeparam name="TEntity">The type of the t entity.</typeparam>
        /// <param name="entity">The entity.</param>
        public virtual void Modify<TEntity>(TEntity entity) where TEntity : BaseEntity
        {
            entity.ModifyTime = DateTime.Now;
            this.Entry(entity).State = EntityState.Modified;
        }

        /// <summary>
        /// 删除对象
        /// </summary>
        /// <typeparam name="TEntity">The type of the t entity.</typeparam>
        /// <param name="entity">The entity.</param>
        public virtual void Remove<TEntity>(TEntity entity) where TEntity : BaseEntity
        {
            this.Set<TEntity>().Remove(entity);
        }

        /// <summary>
        /// 批量删除
        /// </summary>
        /// <typeparam name="TEntity">The type of the t entity.</typeparam>
        /// <param name="entities">The entities.</param>
        public virtual void Remove<TEntity>(IEnumerable<TEntity> entities) where TEntity : BaseEntity
        {
            this.Set<TEntity>().RemoveRange(entities);
        }


        /// <summary>
        /// 添加
        /// </summary>
        /// <typeparam name="TEntity">The type of the t entity.</typeparam>
        /// <param name="entities">The entities.</param>
        public virtual void Add<TEntity>(IEnumerable<TEntity> entities) where TEntity : BaseEntity
        {
            entities.ForEach(x => x.AddTime = DateTime.Now);
            this.Set<TEntity>().AddRange(entities);
        }

        /// <summary>
        /// 批量添加
        /// </summary>
        /// <typeparam name="TEntity">The type of the t entity.</typeparam>
        /// <param name="entity">The entity.</param>
        public virtual void Add<TEntity>(TEntity entity) where TEntity : BaseEntity
        {
            entity.AddTime = DateTime.Now;
            this.Set<TEntity>().Add(entity);
        }

        /// <summary>
        /// 执行返回查询语句
        /// </summary>
        /// <typeparam name="TEntity">The type of the t entity.</typeparam>
        /// <param name="sqlQuery">The SQL query.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns>IEnumerable&lt;TEntity&gt;.</returns>
        public IEnumerable<TEntity> ExecuteQuery<TEntity>(string sqlQuery, params object[] parameters)
        {
            return Database.SqlQuery<TEntity>(sqlQuery, parameters);
        }

        /// <summary>
        /// 执行sql语句
        /// </summary>
        /// <param name="sqlCommand"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public int ExecuteCommand(string sqlCommand, params object[] parameters)
        {
            return Database.ExecuteSqlCommand(sqlCommand, parameters);
        }

        public TEntity Get<TEntity, TKey>(TKey id) where TEntity : BaseEntity
        {
            var entities = this.GetAll<TEntity>();
            return entities.FirstOrDefault(x => x.Id.ToString().Equals(id.ToString()));
        }

        public IQueryable<TEntity> GetAllMatching<TEntity>(ISpecification<TEntity> specification) where TEntity : BaseEntity
        {
            return GetAll<TEntity>().Where(specification.SatisfiedBy());
        }

        public DataPageList<TEntity> GetPageList<TEntity, TK>(int pageIndex, int pageSize, ISpecification<TEntity> specification,
            Expression<Func<TEntity, TK>> orderByExpression, SortEnum sortOrder) where TEntity : BaseEntity
        {
            return this.GetPageList(this.GetAll<TEntity>(), pageIndex, pageSize, specification,
                orderByExpression, sortOrder);
        }

        public DataPageList<TEntity> GetPageList<TEntity, TK>(IQueryable<TEntity> entities, int pageIndex, int pageSize, ISpecification<TEntity> specification,
            Expression<Func<TEntity, TK>> orderByExpression, SortEnum sortOrder) where TEntity : BaseEntity
        {
            var efContext = entities;
            var skip = pageSize * (pageIndex - 1);
            var take = pageSize;
            var totalCount = 0;


            if (skip == 0)
            {
                totalCount = efContext.Count(specification.SatisfiedBy());
            }

            switch (sortOrder)
            {
                case SortEnum.Asc:
                    var pagedGroupAscending =
                        efContext.Where(specification.SatisfiedBy())
                            .OrderBy(orderByExpression)
                            .Skip(skip)
                            .Take(take);

                    return new DataPageList<TEntity>()
                    {
                        PageSize = pageSize,
                        Page = pageIndex,
                        Records = totalCount,
                        Rows = pagedGroupAscending.ToList()
                    };

                case SortEnum.Desc:
                    var pagedGroupDescending =
                        efContext
                            .Where(specification.SatisfiedBy())
                            .OrderByDescending(orderByExpression)
                            .Skip(skip)
                            .Take(take);
                    return new DataPageList<TEntity>()
                    {
                        PageSize = pageSize,
                        Page = pageIndex,
                        Records = totalCount,
                        Rows = pagedGroupDescending.ToList()
                    };
                case SortEnum.Original:
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(sortOrder), sortOrder, null);
            }
            return null;
        }

        public void Modify<TEntity>(IEnumerable<TEntity> entities) where TEntity : BaseEntity
        {
            entities.ForEach(Modify);
        }

        public void Modify<TEntity>(ISpecification<TEntity> specification,
            Expression<Func<TEntity, TEntity>> value) where TEntity : BaseEntity, new()
        {
            GetAllMatching(specification).Set(value).ForEach(Modify);
        }

        public void Remove<TEntity>(ISpecification<TEntity> specification) where TEntity : BaseEntity
        {
            var matchingEntities = GetAllMatching(specification);
            this.Remove(matchingEntities.AsEnumerable());
        }

        public virtual void Remove<TEntity, TKey>(TKey id) where TEntity : BaseEntity
        {
            Remove<TEntity>(new DirectSpecification<TEntity>(x => x.Id.ToString() == id.ToString()));
        }

        #endregion

        /// <summary>
        /// Called when [model creating].
        /// </summary>
        /// <param name="modelBuilder">The model builder.</param>
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
                            .Where(type => !string.IsNullOrEmpty(type.Namespace))
                            .Where(type => type.BaseType != null)
                            .Where(type => type.BaseType.IsGenericType)
                            .Where(type => type.BaseType.GetGenericTypeDefinition() == typeof(EntityBaseTypeConfiguration<>));
            foreach (var type in typesToRegister)
            {
                dynamic configurationInstance = Activator.CreateInstance(type);
                modelBuilder.Configurations.Add(configurationInstance);
            }
            base.OnModelCreating(modelBuilder);
        }
    }
}
